JavaScript 事件模型系列(一)事件与事件处理程序

基本定义

事件: 事件就是浏览器或者用户执行的某种动作,比如文档加载完毕(load)、鼠标点击(click)等等。

事件处理程序: 事件处理程序是响应事件的函数。事件处理程序可以看做是动作的结果,比如文档加载完毕或者点击鼠标之后会发生什么。

为一个事件添加事件处理程序有四种方式。分别为:HTML、DOM0级、DOM2级、IE。

事件处理程序

HTML 事件处理程序

最开始学习 JavaScript 的时候,用到的就是 HTML 事件处理程序,就是直接在 HTML 代码中添加事件处理程序。

比如直接在 HTML 标签内添加:

1
<button id="btn" onclick="console.log('clicked');">Click Me</button>

或添加到 script 标签中(外部 js 文件):

1
2
3
4
5
6
<button id="btn" onclick="show();"></button>
<script>
function show() {
console.log("clicked");
}
</script>

优点:

1
2
3
<button id="btn" onclick="console.log(event.type);">Click Me</button> // click
<button id="btn" onclick="console.log(this.id);">Click Me</button> // btn
  1. 可以通过 event 函数直接访问事件对象,比如 event.type

  2. 在函数内部,this 指向事件的目标元素,在上面第二行代码中,this 指向的就是这个 button 元素

  3. 事件处理程序中的代码在执行时,有权访问到全局作用域中的任何代码,这就是为什么我们可以把函数定义在 script 中,同样也可以调用

缺点:

  1. 时差问题: 用户可能在 HTML 元素一出现就触发事件,而此时该事件的脚本可能还没有加载完成

  2. HTML 与 JavaScript 代码紧密耦合

DOM0 级事件处理程序

将一个函数赋值给一个事件处理程序属性。比如:

1
2
3
4
5
6
<button id="btn"">Click Me</button>
var btn = document.getElementById("btn");
btn.onclick = function() {
console.log("clicked");
}

在 DOM0 级事件处理程序中,this 指向的是这个对象。

优点: HTML 与 JavaScript 代码联系不紧密。

缺点: 不能给一个元素同时添加多个相同的事件处理程序,后添加的事件事件处理程序会覆盖之前的。

1
2
3
4
5
6
7
btn.onclick = function() {
console.log("clicked1");
}
btn.onclick = function() {
console.log("clicked2");
}
// clicked2

DOM2级事件处理程序

DOM2 级事件处理程序用到的是 addEventListenter 方法。

1
element.addEventListener(type,handler,ture/false);

注意在 DOM2 级事件处理程序中,type 是不带 on 的,handler 是事件处理函数,true 表示在捕获阶段调用事件处理程序,false 表示在冒泡阶段调用。

1
2
3
4
5
6
7
<button id="btn"">Click Me</button>
var btn = document.getElementById("btn");
btn.addEventListener("click",function() {
console.log("clicked");
},false); // 冒泡阶段调用

移除:通过 addEventListenter() 添加的事件处理程序,只能通过 removeEventListenter() 移除。

1
2
3
4
5
var handler = function() {
console.log("clicked");
}
btn.addEventListener("click",handler,false); // 添加
btn.removeEventListener("click",handler,false); // 移除

优点:

  1. 可以一个事件添加多个事件处理程序

  2. 浏览器支持性好

  3. HTML 与 JavaScript 代码联系不紧密

1
2
3
4
5
6
7
8
9
10
11
12
<button id="btn"">Click Me</button>
var btn = document.getElementById("btn");
btn.addEventListener("click",function() {
console.log("clicked1");
},false);
btn.addEventListener("click",function() {
console.log("clicked2");
},false);
// clicked1 clicked2

缺点:

  1. 通过 addEventListenter() 添加的匿名函数无法移除

  2. IE8 及以下版本不支持该方法

IE事件处理程序

与 DOM2 级事件处理程序类似,IE 提供了 attachEvent() 和 detachEvent() 方法。不同之处在于,IE 事件处理程序只在冒泡阶段触发。

1
element.attachEvent(type,handler);

注意 IE 事件处理程序,type 要带 on,handler 是事件处理函数。

1
2
3
4
5
var handler = function() {
console.log("clicked");
}
btn.attachEvent("onclick",handler); // 添加
btn.detachEvent("onclick",handler); // 移除

优点:

  1. 可以一个事件添加多个事件处理程序

  2. HTML 与 JavaScript 代码联系不紧密

缺点: 只有 IE 和 Opera 支持。

跨浏览器事件处理程序

为了兼容所有浏览器,我们可以封装一个事件处理程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 绑定事件
var addHandler = function(element,type,handler) {
if (element.addEventListener) {
element.addEventListener(type,handler,false);
}
else if (element.attachEvent){
element.attachEvent("on"+type,handler);
}
else {
element["on"+type]=handler;
}
}
// 移除事件
var reomoveHandler = function(element,type,handler) {
if (element.removeEventListener) {
element.removeEventListener(type,handler,false);
}
else if (element.detachEvent) {
element.detachEvent("on"+type,handler);
}
else {
element["on"+type]=null;
}
}
Fork me on GitHub